﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.ComponentModel;
using SmartRoute.Data;
using SmartRoute.IO;
using SmartRoute.BingMaps;
using SmartRoute.Analytics;
using SmartRoute.Optimization;


namespace SmartRoute.View
{
    /// <summary>
    /// Interaction logic for ProjectPage.xaml
    /// </summary>
    public partial class ProjectPage : Window, INotifyPropertyChanged
    {
        public ProjectPage()
        {
            SplashScreen splash = new SplashScreen("Splash.JPG");
            splash.Show(true);
            _project = BingProject.Reload();
            this.DataContext = this;
            initialize();
            this.InitializeComponent();
            updateImagery();
        }

        private void SaveButton_Click(object sender, RoutedEventArgs e)
        {
            this.save();
            MessageBox.Show("The Project has been saved", "Save", MessageBoxButton.OK);
        }


        private void RunProject_Click(object sender, RoutedEventArgs e)
        {
            if (MessageBox.Show("Run project with the parameters set in the algorithm tab?", "Warning", MessageBoxButton.OKCancel, MessageBoxImage.Warning) == MessageBoxResult.OK)
            {
                _project.AlgorithmState.TraditionalStep();
                updateImagery();
            }
            else { }
        }

        private DateTime _lastSaved = System.DateTime.Now;
        private readonly TimeSpan AutoSaveTime = TimeSpan.FromMinutes(15);

        private void autosave()
        {
            if (DateTime.Now - _lastSaved > AutoSaveTime)
            {
                _project.save();
                _lastSaved = DateTime.Now;
            }
        }

        public void save()
        {
            _project.save();
            _lastSaved = DateTime.Now;
        }

        public IEnumerable<Route> Routes
        {
            get { return _project.BestRoutes; }
        }

        public string SchoolName
        {
            get { return _project.Schools.ToString(); }
        }

        public double BusCost
        {
            get { return _project.Parameters.BaseBusCost; }
            set { _project.Parameters.BaseBusCost = value; Notify("BusCost"); }
        }

        public uint NumberOfBuses
        {
            get { return _project.NumberOfBuses; }
            set { _project.NumberOfBuses = value; Notify("NumberOfBuses"); }
        }
        
        public double TimeCost
        {
            get { return _project.Parameters.TimeCost; }
            set { _project.Parameters.TimeCost = value; Notify("TimeCost"); }
        }
        public double DistanceCost
        {
            get { return _project.Parameters.DistanceCost; }
            set { _project.Parameters.DistanceCost = value; Notify("DistanceCost"); }
        }
        public double PassengerOverloadCost
        {
            get { return _project.Parameters.OverloadCost; }
            set { _project.Parameters.OverloadCost = value; Notify("PassengerOverloadCost"); }
        }
        public double RiderOvertimeCost
        {
            get { return _project.Parameters.OvertimeCost; }
            set { _project.Parameters.OvertimeCost = value; Notify("RiderOvertimeCost"); }
        }
        public uint PassengerLimit
        {
            get { return _project.Parameters.PassengerLimit; }
            set { _project.Parameters.PassengerLimit = value; Notify("PassengerLimit"); }
        }

        public double RiderTimeLimit
        {
            get { return _project.Parameters.RidingTimeLimit.TotalMinutes; }
            set { _project.Parameters.RidingTimeLimit = TimeSpan.FromMinutes(value);
                    Notify("RiderTimeLimit"); }
        }


        public double MutationRate
        {
            get { return _project.MutationRate; }
            set {_project.MutationRate = value;Notify("MutationRate"); }
        }

        public uint PopulationSize
        {
            get { return _project.PopulationSize; }
            set { _project.PopulationSize = value; Notify("PopulationSize"); }
        }

        private void initialize()
        {
            _schoolUpdater = new SchoolUpdater(new Action(this.NotifySchool), _project);
        }

        private void NotifySchool() { Notify("School"); }

        private BingProject _project;

        private class SchoolUpdater : IList<School>, System.Collections.IList
        {
            private BingProject pointerUp;
            private List<School> schoolList;
            private Action Notify;

            public SchoolUpdater(Action notifier, BingProject pointerToProject)
            {
                Notify = notifier;
                pointerUp = pointerToProject;
                schoolList = pointerToProject.Schools.ToList();
            }

            #region IList<School> Members

            public int IndexOf(School item)
            {
                int i = 0;
                foreach(School school in schoolList) if (school.Equals(item)) return i;
                return -1;
            }

            public void Insert(int index, School item)
            {
                this.schoolList.Insert(index, item);
                this.pointerUp.addSchool(item);
                Notify();
            }

            public void RemoveAt(int index)
            {
                var school = this[index];
                this.schoolList.RemoveAt(index);
                this.pointerUp.removeSchool(school);
            }

            public School this[int index]
            {
                get
                {
                    return schoolList[index];
                }
                set
                {
                    var school = schoolList[index];
                    if (!this.Contains(value))
                    {
                        schoolList[index] = value;
                    }
                    else
                    {
                        this.Remove(value);
                        this.Insert(index, value);
                    }
                    pointerUp.removeSchool(school);
                    Notify();
                }
            }

            public string toString()
            {
                return this.toString();
            }

            #endregion

            #region ICollection<School> Members

            public void Add(School item)
            {
                if (!this.Contains(item))
                {
                    schoolList.Add(item);
                    pointerUp.addSchool(item);
                    Notify();
                }
            }

            public void Overwite(IEnumerable<School> schools)
            {
                schoolList.Clear();
                foreach (var school in pointerUp.Schools) pointerUp.removeSchool(school);
                foreach (var sch in schools)
                {
                    schoolList.Add(sch);
                    pointerUp.addSchool(sch);
                }
                Notify();
            }

            public void Clear()
            {
                schoolList.Clear();
                foreach (var school in pointerUp.Schools) pointerUp.removeSchool(school);
                Notify();
            }

            public bool Contains(School item)
            {
                return schoolList.Contains(item);
            }

            public void CopyTo(School[] array, int arrayIndex)
            {
                int i = arrayIndex;
                foreach (var sch in schoolList) array[i++] = sch;
            }

            public int Count
            {
                get { return schoolList.Count; }
            }

            public bool IsReadOnly
            {
                get { return false; }
            }

            public bool Remove(School item)
            {
                if(this.Contains(item))
                {
                    schoolList.Remove(item);
                    pointerUp.removeSchool(item);
                    Notify();
                    return true;
                }
                return false;
            }

            #endregion

            #region IEnumerable<School> Members

            public IEnumerator<School> GetEnumerator()
            {
                return schoolList.GetEnumerator();
            }

            #endregion

            #region IEnumerable Members

            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
            {
                return schoolList.GetEnumerator();
            }

            #endregion

            #region IList Members

            public int Add(object value)
            {
                if (!(value is School)) return -1;
                this.Add((School)(value));
                return this.IndexOf((School)value);
            }

            public bool Contains(object value)
            {
                return value is School && this.Contains((School)value);
            }

            public int IndexOf(object value)
            {
                if (value is School) return this.IndexOf((School)value);
                else return -1;
            }

            public void Insert(int index, object value)
            {
                if (value is School) this.Insert(index, (School)value);
            }

            public bool IsFixedSize
            {
                get { return false; }
            }

            public void Remove(object value)
            {
                if (value is School) this.Remove((School)value);
            }

            object System.Collections.IList.this[int index]
            {
                get
                {
                    return this[index];
                }
                set
                {
                    if (value is School) this[index] = (School)value;
                }
            }

            #endregion

            #region ICollection Members

            public void CopyTo(Array array, int index)
            {
                this.CopyTo((School[])array, index);
            }

            public bool IsSynchronized
            {
                get { return false; }
            }

            public object SyncRoot
            {
                get { return this; }
            }

            #endregion
        }

        private SchoolUpdater _schoolUpdater;

        public IList<School> Schools
        {
            get { return _schoolUpdater; }
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler  PropertyChanged;
        
        protected void Notify(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
            autosave();
        }

        #endregion

        private void StopComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            NumPassengers.IsReadOnly = false;
            Lat.IsReadOnly = false;
            Long.IsReadOnly = false;
            Pass2.IsReadOnly = true;
            Lat2.IsReadOnly = true;
            Long2.IsReadOnly = true;
            AddStopToSchool.IsEnabled = false;
            DELETE.IsEnabled = true;

            if (StopComboBox.SelectedItem != null)
            {
                Lat.Text = ((Stop)(StopComboBox.SelectedItem)).Latitude.ToString();
                Long.Text = ((Stop)(StopComboBox.SelectedItem)).Longitude.ToString();
                NumPassengers.Text = ((Stop)(StopComboBox.SelectedItem)).Passengers.ToString();
            }
            else
            {
                Lat.Text = "";
                Long.Text = "";
                NumPassengers.Text = "";

                NumPassengers.IsReadOnly = true;
                Lat.IsReadOnly = true;
                Long.IsReadOnly = true;
            }
        }

        private void EditStop_Click(object sender, RoutedEventArgs e)
        {
            int numPass = Int32.Parse(NumPassengers.Text);
            double lati = Double.Parse(Lat.Text);
            double longi = Double.Parse(Long.Text);

            ((School)(SchoolNameComboBox.SelectedItem))
                .relocateStop((Stop)(StopComboBox.SelectedItem),new Location(lati,longi,""), numPass);

            Notify("School");

            Notify("SelectedItem.Stops");
        }

        private void SchoolNameComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            //StopComboBox.SelectedItem = StopComboBox.Items.GetItemAt(0);
            Pass2.IsReadOnly = false;
            Lat2.IsReadOnly = false;
            Long2.IsReadOnly = false;
            AddStopToSchool.IsEnabled = true;

        }

        private void AddStopToSchool_Click(object sender, RoutedEventArgs e)
        {
            double lati = Double.Parse(Lat2.Text);
            double longi = Double.Parse(Long2.Text);
            int passen = Int32.Parse(Pass2.Text);

            ((School)(SchoolNameComboBox.SelectedItem)).addToStop(new Location(lati, longi, ""), passen);              

            Notify("School");

            Notify("SelectedItem.Stops");
        }

        private void DELETE_Click(object sender, RoutedEventArgs e)
        {
            double lati = Double.Parse(Lat.Text);
            double longi = Double.Parse(Long.Text);

            ((School)(SchoolNameComboBox.SelectedItem)).clearStop(new Location(lati,longi,""));

            Notify("School");

            Notify("SelectedItem.Stops");
        }

        private void PrintDirections_Click(object sender, RoutedEventArgs e)
        {
            PrintUsingCondensed(Directions.Text, "");

        }

        private void PrintUsingCondensed(string text, string caption)
        {
            FlowDocument doc = new FlowDocument(new Paragraph(new Run(text)));
            doc.PagePadding = new Thickness(100);

            PrintDialog printing = new PrintDialog();

            printing.PrintDocument(
                ((IDocumentPaginatorSource)doc).DocumentPaginator, caption);
        }

        private Imagery routeDisplay;

        public ImageSource MapImage
        {
            get { return routeDisplay.MapImage; }
        }

        public GeometryGroup RouteLines
        {
            get { return routeDisplay.DrawnRoutesGrouping; }
        }

        private void updateImagery()
        {
            routeDisplay = new Imagery(_project.BestRoutes);
            Notify("RouteLines");
            Notify("MapImage");
        }

        private void comboBox2_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            Directions.Text = ((Route)comboBox2.SelectedItem).Directions;
            
        }

        private void RouteSchoolNameComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            //comboBox2.Items.Add(_project.BestRoutes);
        }
    
    }
}

